/****************************************

This file is part of the Dynamo CMS UI Toolkit
Copyright (c) Dynamo Studios 2008

*NOTE*

Permission is hereby granted to execute this file as a
web service under the terms of the license agreement.

See LICENSE.txt, in the system folder.

All other rights, other than those expressed in the license
document, are reserved.

See LICENSE.txt, in the system folder.

All other rights, other than those expressed in the license
document, are reserved.

****************************************/

/*
 * Script: 	AJAX Request Manager
 * Version: 0.1 (Alvin)
 * Provides:
 *  - A request queue, for the stacking of AJAX requests.
 *  - Request history, allowing requests to be re-run, hence
 *    giving browser back-button support.
 *  - Object modification history, allowing requests which
 *    modify objects to be reverted, giving undo support.
 *
 * Author: Sean Micklethwaite
 */

/*
	Class: AjaxRequest
	Not yet documented.
*/
var AjaxRequest = new Class({
    request: null,
	options: null,
	meta:	 {},

	initialize: function(opts){
        this.options = opts;
    },

    OnComplete: function(event){
    	ieButtonHackCleanup();
		
		// pick meta tag (hidden div) (only X-dycms)
		tmp = new Element('div');
		tmp.setHTML(this.request.response.text);
		tmp.getElements('div[id=Xdycms]').each( function(m) {
			console.log(m.getText());
			this.meta = Json.evaluate(m.getText());
			m.remove();
		}.bind(this));
		this.request.response.text = tmp.innerHTML;
    	
		// Check for override
		if($defined(this.meta.ajaxOverride)
			&& (this.meta.ajaxOverride != '')){
			window.location = this.meta.ajaxOverride;
			return;
		}
		
		// callbacks
        if(this.options.preCallback)
            this.options.preCallback(this);

        if(this.options.callback)
            this.options.callback(this);

        if(this.options.postCallback)
            this.options.postCallback(this);
    }
});

/*
	Class: AjaxGetRequest
	Not yet documented.
	
	Extends:
		<AjaxRequest>
*/
var AjaxGetRequest = AjaxRequest.extend({
	initialize: function(oGetArgs, opts){
		opts.method = 'GET';
        opts.queryUrl = (opts.raw
        	? "/private/system/public/rawrq.php?"
        	: "/private/system/public/xmlrq.php?")
            + Object.toQueryString(oGetArgs);
        
        this.parent(opts);
    },
    
	Dispatch: function(oPre, oPost){
	/**
     * Dispatches the GET request.
     **/

     	if(oPre) this.options.preCallback = oPre;
        if(oPost) this.options.postCallback = oPost;
        
        //
        // Send the request
        //
        
        this.request = new Ajax(this.options.queryUrl,{
        	evalScripts: false,
        	onComplete: this.OnComplete.bind(this),
        	update: this.options.update
		});
        
        this.request.request();
	}
});

/*
	Class: AjaxPost
	Not yet documented.
	
	Extends:
		<AjaxGetRequest>
*/
var AjaxPostRequest = AjaxGetRequest.extend({
    initialize: function(vzPostArgs, vzGetArgs, opts){
        this.parent(vzGetArgs, opts)
        this.postArgs = vzPostArgs;
    },

    Dispatch: function(oPre, oPost){
    /**
     * Dispatches the POST request.
     **/

        if(oPre) this.options.preCallback = oPre;
        if(oPost) this.options.postCallback = oPost;

        //
        // Create form to hold our POST vars
        //

        frm = new Element('form', {
            action: this.options.queryUrl,
            method: 'POST'
        });

        //
        // Add hidden elements to store values
		// Use textareas so new lines are properly handled
		// by IE.
        //

        $each(this.postArgs, function(sValue, sName){
            frm.adopt(new Element('textarea',{
                name: sName,
                id: sName,
				value: sValue
            }));
        });

        this.request = frm.send({
            evalScripts: false,
            onComplete: this.OnComplete.bind(this)
        });
    }
});


/*
	Class: AjaxRequestMgr
	Not yet documented.
*/
var AjaxRequestMgr = new Class({

    // Stores requests
    requestPending: false,
    requestQueue: Array(),
    nextRequest: 0,
    numRequests: 0,

    // Currently executing request
    currentRequest: null,
    currentCallback: null,

    QueueRequest: function($o){
    	this.requestQueue[this.numRequests++] = $o;
	},
	
    Execute: function(oCallback){
    /**
     * Dispatches all queued AjaxRequests, calling the given
     * callback routine when finished.
     **/

        this.currentCallback = oCallback;

        this.__dispatch = function(){
            this.currentRequest = this.requestQueue[this.nextRequest++];
            this.currentRequest.Dispatch(this.__complete,
            	((this.nextRequest == this.numRequests)
            		? this.currentCallback : null));
        }.bind(this);

        this.__complete = function(){
            if(this.nextRequest < this.numRequests)
            	// Dispatch the next request
                this.__dispatch();
            else{
                this.currentRequest = null;
            };
        }.bind(this);
        

        //
        // Flush the queue
        //

        this.__complete();
    },

    Dispatch: function(oRequest){
    /**
     * Dispatches a one-off AjaxRequest. Fails if there
     * is a queue of requests waiting.
     **/

        if(this.nextRequest < this.numRequests){
            alert("Error - your actions have not yet been committed.");
            return false;
        };


        this.currentRequest = oRequest;
        this.currentRequest.Dispatch(null, function(){
        	this.currentRequest = null;
		});
    },
    
    
    /** Utility Routines **/
    
    GetQueryArgs: function(url){
    /**
     * Returns an associative array giving the current page's querystring.
     **/
     	var zArgs = Object();
     	var args = new String(url);
     	
     	if(args.indexOf('?') != -1)
	     	args = args.slice(args.indexOf('?') + 1);
	    else
	    	return null;
	    
     	args = args.split('&');
     	for(var i=0; i<args.length; i++){
     		args[i] = args[i].split('=');
     		zArgs[this.UrlDecode(args[i][0])] = this.UrlDecode(args[i][1]);
     	}
     	
     	return zArgs;
    },
    
    GetCurrentQueryArgs: function(){
    	return this.GetQueryArgs(window.location);
    },
    
    UrlDecode: function(str){
     	return unescape(str.replace(/\+/g, " "));
    }
});

// Section: Globals
//
// Variable: ajaxRq
// Global Ajax Request Manager
var ajaxRq = new AjaxRequestMgr();